package utile

import (
	"context"
	"errors"
	"fmt"
	"go.etcd.io/etcd/clientv3"
	"time"
)

type Etcd struct {
	address string
	prefix string
	status bool
	keys []string
}

type Edata struct {
	Key string `json:"key"`
	Val string `json:"val"`
}

var etcd = &Etcd{}

func InitEtcd(address,prefix string) {
	etcd.address = address
	etcd.prefix = prefix
	etcd.keys = make([]string,10)
}

func GetEtcd() *Etcd {
	return etcd
}


func (e *Etcd) GetEtcdClient() (*clientv3.Client,error){
	cli,err := clientv3.New(clientv3.Config{
		Endpoints:   []string{etcd.address},
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		return nil, errors.New("connect etcd failed")
	}
	return cli,nil
}

func (e *Etcd) Set(key,val string) error {
	cli,err := e.GetEtcdClient()
	defer func() {
		cli.Close()
	}()
	if err != nil {
		return err
	}
	ctx,cancel := context.WithTimeout(context.Background(),time.Second)
	_,err = cli.Put(ctx,key,val)
	cancel()
	if err != nil {
		return errors.New(fmt.Sprintf("etcd set data failed , err: %s",err))
	}
	e.keys = append(e.keys,key)
	return nil
}

func (e *Etcd) Get(key string) (edata Edata,err error) {
	cli,err := e.GetEtcdClient()
	defer func() {
		cli.Close()
	}()
	if err != nil {
		return edata,err
	}
	ctx,cancel := context.WithTimeout(context.Background(),time.Second)
	resp,err := cli.Get(ctx,key)
	cancel()
	edata = Edata{}
	if err != nil {
		return edata,errors.New(fmt.Sprintf("etcd get data failed , err: %s",err))
	}
	for _, ev := range resp.Kvs {
		edata.Key = string(ev.Key)
		edata.Val = string(ev.Value)
		//fmt.Printf("%s:%s\n", ev.Key, ev.Value)
	}
	return edata,nil
}

func (e *Etcd) GetAllKeyByPrefix(prefix string) ([]Edata,error) {
	cli, err := e.GetEtcdClient()
	defer func() {
		cli.Close()
	}()
	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	resp, err := cli.Get(ctx, prefix, clientv3.WithPrefix())
	cancel()
	if err != nil {
		return nil, errors.New(fmt.Sprintf("connect etcd failed , err: %s",err))
	}
	keys := make([]Edata,0)
	for _, ev := range resp.Kvs {
		edata := Edata{string(ev.Key),string(ev.Value)}
		keys = append(keys,edata)
	}
	return keys,nil
}

func (e *Etcd) Del(key string) error {
	cli, err := e.GetEtcdClient()
	defer func() {
		cli.Close()
	}()
	if err != nil {
		return err
	}
	ctx,cancel := context.WithTimeout(context.Background(),time.Second)
	_,err = cli.Delete(ctx,key)
	cancel()
	if err != nil {
		return errors.New(fmt.Sprintf("etcd del failed , err: %s",err))
	}
	return nil
}

